package com.ftg.mall.base.util.tools;


import com.ftg.mall.base.util.tooltips.TipEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.lang.reflect.*;
import java.util.*;
/**
 * @author wangty
 * @date 2022/11/16
 */
@SuppressWarnings("all")
public class ConvertUtil {

    private static final Logger log = LoggerFactory.getLogger(ConvertUtil.class);

    /**
     * 根据业务需求完成树形功能转换
     *     将Entity转换成为对应的 Vo的方法
     * @param list   通过数据库查询出来的结果
     * @param vo     vo包里面的类型
     * @param <Vo>   自己创建的vo类型
     * @param <Entity>  数据表对应实体
     * @return
     */
    public static <Vo,Entity> List<Vo> convertClass(List<Entity> list,Class<Vo> vo) {
        return convertClass("id","parentId","children",-1L,list,vo);
    }

    /**
     *
     * @param id      树形结构的主键
     * @param pid     树形结构的父主键
     * @param children 树形结构子元素存储的字段名称
     * @param root     顶级节点的值 如-1
     * @param list     数据库里表里面的全部节点
     * @param vo       返回信息
     * @param <Vo>     泛型  vo包里面的类
     * @param <Entity> 泛型 entity包里面的类
     * @return
     */
    public static <Vo,Entity> List<Vo> convertClass(String id,String pid,String children,Long root,List<Entity> list,Class<Vo> vo) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("get").append(id.substring(0,1).toUpperCase(Locale.ROOT)).append(id.substring(1));
        String idGetName = stringBuilder.toString();

        StringBuilder stringBuilder1 = new StringBuilder();
        stringBuilder1.append("get").append(pid.substring(0,1).toUpperCase(Locale.ROOT)).append(pid.substring(1));
        String pidGetName = stringBuilder1.toString();


        //最终返回结构
        List<Vo> result = new ArrayList<>();
//       循环所有
        for (Entity productCategory : list) {
            // 查询数据里面所有parent_id为-1的
            Object pidObject = null;
            //取相应的父id方法返回值
            try {
                Method temp = productCategory.getClass().getMethod(pidGetName);
                pidObject =temp.invoke(productCategory);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                log.error("没有找到父id所对应的getter方法，请查看实例");
                e.printStackTrace();
            }
            //最终取到的父id的值
            Long parentId = (Long) pidObject;
            if(parentId.equals(root)){
                //找到数据以后直接转换类型
                Vo temp = ConvertUtil.convertTwoClass(vo,productCategory);
                //加入最终集合里
                result.add(temp);
                //找当前的parentid为-1 ProductCategory分类，然后再查找这个节点的子节点
                findSon(idGetName,pidGetName,children,temp,list);
            }
        }
        return result;
    }

    /**
     *
     * @param id      树形结构的主键
     * @param pid     树形结构的父主键
     * @param children 树形结构子元素存储的字段名称
     * @param temp     树的当前节点
     * @param list     数据库里表里面的全部节点
     * @param <Vo>     返回信息
     * @param <Entity> 实体信息
     */
    private static  <Vo,Entity> void findSon(String id,String pid,String children,Vo temp, List<Entity> list)  {
        StringBuilder stringBuilder2 = new StringBuilder();
        stringBuilder2.append("get").append(children.substring(0,1).toUpperCase(Locale.ROOT)).append(children.substring(1));
        String childrenGetName = stringBuilder2.toString();

        StringBuilder stringBuilder3 = new StringBuilder();
        stringBuilder3.append("set").append(children.substring(0,1).toUpperCase(Locale.ROOT)).append(children.substring(1));
        String childrenSetName = stringBuilder3.toString();

        //循环
        for (Entity productCategory : list) {
            //当前节点的temp的id与其它人的parentId是否相同
            Class<Vo> tempClass = (Class<Vo>) temp.getClass();
            Method idMethod = null;
            try {
                //取当前主键的值
                idMethod = tempClass.getMethod(id);
                Object obj = idMethod.invoke(temp);
                //最终主键的值
                Long idVal = Long.valueOf(obj.toString());
                //取父id的值
                Method parentIdMethod = productCategory.getClass().getMethod(pid);
                //最终父id的值
                Long pidVal = (Long) parentIdMethod.invoke(productCategory);
                // 判断是否为子项
                if(idVal.equals(pidVal)){
                    //取父id的值
                    Method childMethod = tempClass.getMethod(childrenGetName);
                    //判断父id是否为null
                    List<Vo> childrenVal = (List<Vo>) childMethod.invoke(temp);
                    // children为空的处理
                    if(childrenVal == null){
                        Method setChildMethod = tempClass.getMethod(childrenSetName,List.class);
                        setChildMethod.invoke(temp,new ArrayList<>());
                    }
                    // 类型转换
                    Vo temp1 = ConvertUtil.convertTwoClass(tempClass,productCategory);
                    // 取到有值以后的children方法
                    List<Vo> childrenVal1 = (List<Vo>) childMethod.invoke(temp);
                    //添加到 children
                    childrenVal1.add(temp1);
                    //递归
                    findSon(id,pid,children,temp1,list);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     *  泛型是对类型的一个可变化处理
     * 方法泛型 : 静态方法泛型
     * @param e 表示你要转换成为哪一个类型
     * @param t2  你要把哪一个类型里面的数据存储到E里面,这一定是一个有值的对象  它有一个父类 id在baseEntity里面呢,你没有取出来
     * @param <E>  vo的类型
     * @param <T>  实体类型
     * @return vo类型
     */
    public static <E,T>  E convertTwoClass(Class<E> e,T t2){
        Assert.notNull(t2, TipEnum.FAIL_PARAMETERTYPE_REFLECH_TIP);
        Assert.notNull(e, TipEnum.FAIL_PARAMETERTYPE_REFLECH_TIP);

        //就是我们目标类的实例呀
        Object object = null;
        try {
            object = e.newInstance();
            Class<T> convertClass = (Class<T>) t2.getClass();
            //取出目标类里面的所有方法
            Method[] targetMethod = e.getMethods();
            for (Method method : targetMethod) {
                //取出所有set 方法  setId  idSet
                String methodName = method.getName();
                if(methodName.contains("set") && methodName.startsWith("set")){
                    //这个setter方法执行完成以后，就是setter对应的属性赋值了 getter取的时候就有值
                    //就是转换类里面的getter方法名称
                    String convertMethodName = "get" + methodName.substring(3);
                    //取转换类里的方法
                    Method convertMethod = null;
                    try {
                        convertMethod = convertClass.getMethod(convertMethodName);
                    }catch (Exception ex){
                        continue;
                    }

                    Object val = convertMethod.invoke(t2);
                    method.invoke(object,val);
                }
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException  instantiationException) {
            instantiationException.printStackTrace();
        }
        return (E)object;
    }
}
